package dispatcher

import (
	"google.golang.org/protobuf/proto"

	"gitee.com/hasika/common-server/codec"
	"gitee.com/hasika/common-server/conn/inet"
	"gitee.com/hasika/common-server/option"
	"gitee.com/hasika/common-server/session"
	"gitee.com/hasika/gotool/errorx"
	"gitee.com/hasika/gotool/logx/stdlog"
)

var Log = stdlog.NewDefaultLog()

type ProtoMessageDispatcher struct {
	router         *option.ProtoMessageRouter
	sessionManager *session.Manager
}

func (s *ProtoMessageDispatcher) DispatchMessage(packet codec.Packet, conn inet.Conn) {
	replyErr, replyMsg, nilMustReply, replyConnType := s.handle(packet, conn)
	if replyErr == nil && replyMsg == nil && !nilMustReply {
		return
	}
	s.sessionManager.SendToClientByType(packet.GetUid(), packet, replyErr, replyMsg, replyConnType, conn)
}

func (s *ProtoMessageDispatcher) CanHandle(packet codec.Packet, conn inet.Conn) bool {
	message := packet.GetMessage()
	if message == nil {
		return false
	}
	info := s.router.Get(packet)
	return info != nil
}

func (s *ProtoMessageDispatcher) handle(packet codec.Packet, conn inet.Conn) (errorx.IError, proto.Message, bool, inet.ConnectionType) {
	routerIndex := packet.GetMessage().ProtoReflect().Type()
	info := s.router.Get(packet)
	if info == nil {
		return errorx.NewStringErr("proto not registered"), nil, true, inet.Source
	}
	if info.Handler == nil {
		Log.Errorf("proto not registered %d", routerIndex)
		return errorx.NewStringErr("proto not registered"), nil, true, info.ReplyType
	}
	replyErr, replyMsg := info.Handler(packet, conn)
	return replyErr, replyMsg, info.NilMustReply, info.ReplyType
}

func NewProtoMessageDispatcher(router *option.ProtoMessageRouter, sessionManager *session.Manager) *ProtoMessageDispatcher {
	return &ProtoMessageDispatcher{
		router:         router,
		sessionManager: sessionManager,
	}
}
